#include "PlotView.h"
#include <cmath>
#include <sstream>
#include <iomanip>
#include<iostream>

PlotView::PlotView(int panelWidth, int screenWidth, int screenHeight)
    : m_panelWidth(panelWidth),
    m_screenWidth(screenWidth),
    m_screenHeight(screenHeight),
    m_plotWidth(screenWidth - panelWidth) {}

int PlotView::toScreenX(double worldX) const {
    worldX = max(0.0, worldX); 
    return static_cast<int>((worldX - m_viewState.centerX) * m_viewState.zoom + m_plotWidth / 2) + m_panelWidth;
}

int PlotView::toScreenY(double worldY) const {
    worldY = max(0.0, worldY); // 不需要负坐标
    return static_cast<int>(m_screenHeight / 2 - (worldY - m_viewState.centerY) * m_viewState.zoom);
}

double PlotView::toWorldX(int screenX) const {
    return (screenX - m_panelWidth - m_plotWidth / 2) / m_viewState.zoom + m_viewState.centerX;
}


double PlotView::toWorldY(int screenY) const {
    return m_viewState.centerY - (screenY - m_screenHeight / 2) / m_viewState.zoom;
}

void PlotView::setViewCenter(double x, double y) {
    m_viewState.centerX = x;
    m_viewState.centerY = y;
}

void PlotView::getViewCenter(double& x, double& y) const {
    x = m_viewState.centerX;
    y = m_viewState.centerY;
}

void PlotView::setZoom(double zoom) {
    m_viewState.zoom = max(0.001, min(1000.0, zoom));
}

double PlotView::getZoom() const {
    return m_viewState.zoom;
}

void PlotView::resetView(double x,double y,double zoom) {
    m_viewState.centerX = x;
    m_viewState.centerY = y;
    m_viewState.zoom = zoom;
}

double PlotView::calculateTickInterval(double range) const {
    double interval = pow(10, floor(log10(range / 5)));
    if (range / interval < 3) interval /= 2;
    if (range / interval < 3) interval /= 2.5;
    return max(1.0, interval);
}

void PlotView::drawSingleTick(double value, bool isXAxis) const {
    const COLORREF TICK_COLOR = RGB(100, 100, 100);
    const COLORREF TEXT_COLOR = RGB(200, 200, 200);

    setlinecolor(TICK_COLOR);
    settextcolor(TEXT_COLOR);
    settextstyle(12, 0, _T("宋体"));
    setbkmode(TRANSPARENT);

    if (isXAxis) {
        int sx = toScreenX(value);
        if (sx >= m_panelWidth && sx <= m_screenWidth) {
            line(sx, toScreenY(0) - 5, sx, toScreenY(0) + 5);
            std::wstringstream ss;     
            ss  << value;
            //ss << std::fixed << std::setprecision(value < 10 ? 0 : 1) << value;
            outtextxy(sx - 20, toScreenY(0) + 10, ss.str().c_str());
        }
    }
    else {
        int sy = toScreenY(value);// 确保Y轴刻度在可视范围内
        if (sy >= 0 && sy <= m_screenHeight) {
            line(toScreenX(0) - 5, sy, toScreenX(0) + 5, sy);
            std::wstringstream ss;  
            ss << value;
            //ss << std::fixed << std::setprecision(value < 10 ? 0 : 1) << value;
            outtextxy(toScreenX(0) + 10, sy - 10, ss.str().c_str());
        }
    }
}

void PlotView::drawGridLines(double interval, bool isXAxis) const {
    const COLORREF GRID_COLOR = RGB(60, 60, 60); 
    setlinecolor(GRID_COLOR);

    if (isXAxis) {
        double start = max(0.0, floor(toWorldX(m_panelWidth) / interval) * interval);
        double end = ceil(toWorldX(m_screenWidth) / interval) * interval;

        for (double x = start; x <= end; x += interval) {
            int sx = toScreenX(x);
            if (sx >= m_panelWidth && sx <= m_screenWidth) {
                int y0 = toScreenY(0);
                if (y0 >= 0) {
                    line(sx, y0, sx, 0);
                }
            }
        }
    }
    else {
        double start = max(0.0, floor(toWorldY(m_screenHeight) / interval) * interval);
        double end = ceil(toWorldY(0) / interval) * interval;

        for (double y = start; y <= end; y += interval) {
            int sy = toScreenY(y);
            if (sy >= 0 && sy <= m_screenHeight) {
                int x0 = max(m_panelWidth, toScreenX(0)); 
                line(x0, sy, m_screenWidth, sy);
            }
        }
    }
}

void PlotView::drawAxis() const {
    const COLORREF AXIS_COLOR = RGB(150, 150, 150);
    setlinecolor(AXIS_COLOR);

    int y = toScreenY(0);
    if (y >= 0 && y <= m_screenHeight) {
        line(m_panelWidth, y, m_screenWidth, y);  // X轴
    }

    int x = toScreenX(0);
    if (x >= m_panelWidth && x <= m_screenWidth) {
        line(x, 0, x, m_screenHeight);  // Y轴
    }
}

void PlotView::drawTicks(double interval, bool isXAxis) const {
    if (isXAxis) {
        double start = floor(toWorldX(m_panelWidth) / interval) * interval;
        double end = ceil(toWorldX(m_screenWidth) / interval) * interval;

        for (double x = start; x <= end; x += interval) {
            if (x >= 0 && x <= 65535) {
                drawSingleTick(x, true);
            }
        }
    }
    else {
        double visibleTop = m_viewState.centerY + (m_screenHeight / 2) / m_viewState.zoom;
        double visibleBottom = m_viewState.centerY - (m_screenHeight / 2) / m_viewState.zoom;

        double start = floor(visibleBottom / interval) * interval;
        double end = ceil(visibleTop / interval) * interval;

        for (double y = start; y <= end; y += interval) {
            if (y >= 0 && y <= 65535) {
                drawSingleTick(y, false);
            }
        }
    }
}

void PlotView::drawAxisLabels() const {
    const COLORREF TEXT_COLOR = RGB(200, 200, 200);
    settextcolor(TEXT_COLOR);
    settextstyle(14, 0, _T("宋体"));  // 增大字体

    int yPos = toScreenY(0);
    outtextxy(m_screenWidth - 40, yPos - 25, _T("X轴"));

    int xPos = toScreenX(0);
    if(xPos>= m_panelWidth)
    outtextxy(xPos + 15, 15, _T("Y轴"));
    //// 强制显示原点
    //if (xPos >= m_panelWidth&&abs(m_viewState.centerX) < 100 && abs(m_viewState.centerY) < 100) {
    //    outtextxy(xPos + 10, yPos + 5, _T("(0,0)"));
    //}
}

    double xRange = m_plotWidth / m_viewState.zoom;
    double yRange = m_screenHeight / m_viewState.zoom;

    double xTickInterval = calculateTickInterval(xRange);
    double yTickInterval = calculateTickInterval(yRange);


    drawTicks(xTickInterval, true);  
    int screenX0 = toScreenX(0);
    //(screenX0==750);
    if(screenX0>=m_panelWidth)
    drawTicks(yTickInterval, false); 

    drawGridLines(xTickInterval, true);  
    drawGridLines(yTickInterval, false);

    drawAxis();

    drawAxisLabels();
}

void PlotView::mouseWheel(int mouseX, int mouseY, int wheel) {
    int plotX = mouseX - m_panelWidth;
    //int screenX0 = toScreenX(0);
    //std::cout << m_panelWidth << "  " << mouseX << "  " << mouseY << "\n";
    if (mouseX > m_panelWidth) {

        //double worldX = toWorldX(mouseX);
        //double worldY = toWorldY(mouseY);

        if (wheel > 0) {
            m_viewState.zoom = min(m_viewState.zoom * 1.2, 1000.0);
        }
        else {
            m_viewState.zoom = max(m_viewState.zoom / 1.2, 0.001);
        }
        //m_viewState.centerX = worldX - (plotX - m_plotWidth / 2) / m_viewState.zoom;
        //m_viewState.centerY = worldY - (mouseY - m_screenHeight / 2) / m_viewState.zoom;
    }
}

void PlotView::mouseClick(int mouseX, int mouseY) {
    if (mouseX > m_panelWidth) {
        m_viewState.isDragging = true;
        m_viewState.lastMouseX = mouseX;
        m_viewState.lastMouseY = mouseY;
    }
}

void PlotView::mouseMove(int mouseX, int mouseY) {
    if (m_viewState.isDragging && mouseX > m_panelWidth) {
        double dx = (mouseX - m_viewState.lastMouseX) / m_viewState.zoom;
        double dy = (mouseY - m_viewState.lastMouseY) / m_viewState.zoom;

        double newCenterX = m_viewState.centerX - dx;
        newCenterX = max(0, newCenterX);

        double newCenterY = m_viewState.centerY + dy;
        newCenterY = max(0, newCenterY);

        m_viewState.centerX = newCenterX;
        m_viewState.centerY = newCenterY;

        m_viewState.lastMouseX = mouseX;
        m_viewState.lastMouseY = mouseY;
    }
}

void PlotView::ButtonUp(int mouseX, int mouseY) {
    m_viewState.isDragging = false;
}

//void PlotView::ButtonDblClk(int mouseX, int mouseY) {
//    //if (mouseX > m_panelWidth) 
        //resetView();
//    
//}

void PlotView::handleInput() {}

void PlotView::addDataPoint(double x, double y, const std::wstring& label,
    COLORREF color, int size) {
    m_dataPoints.push_back({ x, y, label, color, size });
}
void PlotView::addLineSegment(double x1, double y1, double x2, double y2,
    COLORREF color, int thickness) {
    m_lineSegments.push_back({ x1, y1, x2, y2, color, thickness });
}

void PlotView::clearAllData() {
    m_dataPoints.clear();
    m_lineSegments.clear();
}

void PlotView::drawAllData() const {
    for (const auto& segment : m_lineSegments) {
        drawLine(segment.x1, segment.y1, segment.x2, segment.y2,
            segment.color, segment.thickness);
    }

    // 绘制数据点
    settextstyle(12, 0, _T("宋体"));
    for (const auto& point : m_dataPoints) {
        //int screenX0 = toScreenX(0);

            drawPoint(point.x, point.y, point.color, point.size);
            if (m_viewState.zoom >= 7) {
            settextcolor(RGB(255, 255, 0));
            outtextxy(toScreenX(point.x) + 5, toScreenY(point.y) - 10, point.label.c_str());
        }
       }
}

void PlotView::drawLine(double x1, double y1, double x2, double y2, COLORREF color, int thickness) const {
    int sx1 = toScreenX(x1);
    int sy1 = toScreenY(y1);
    int sx2 = toScreenX(x2);
    int sy2 = toScreenY(y2);

    if (sx1 < m_panelWidth && sx2 < m_panelWidth) {
        return; 
    }

    if (sx1 < m_panelWidth || sx2 < m_panelWidth) {
        double t = static_cast<double>(m_panelWidth - sx1) / (sx2 - sx1);
        if (sx1 < m_panelWidth) {
            sx1 = m_panelWidth;
            sy1 = sy1 + static_cast<int>(t * (sy2 - sy1));
        }
        else {
            sx2 = m_panelWidth;
            sy2 = sy1 + static_cast<int>(t * (sy2 - sy1));
        }
    }

    setlinecolor(color);
    setlinestyle(PS_SOLID, thickness);
    line(sx1, sy1, sx2, sy2);
}

void PlotView::drawPoint(double x, double y, COLORREF color, int size) const {
    int sx = toScreenX(x);
    int sy = toScreenY(y);
    if (sx >= m_panelWidth &&  sy >= 0 ) {
        setfillcolor(color);
        solidcircle(sx, sy, size);
    }
}

